Task 1

library(ggplot2)
library(tibble)
mpg
## # A tibble: 234 × 11
##    manufacturer model      displ  year   cyl trans drv     cty   hwy fl    class
##    <chr>        <chr>      <dbl> <int> <int> <chr> <chr> <int> <int> <chr> <chr>
##  1 audi         a4           1.8  1999     4 auto… f        18    29 p     comp…
##  2 audi         a4           1.8  1999     4 manu… f        21    29 p     comp…
##  3 audi         a4           2    2008     4 manu… f        20    31 p     comp…
##  4 audi         a4           2    2008     4 auto… f        21    30 p     comp…
##  5 audi         a4           2.8  1999     6 auto… f        16    26 p     comp…
##  6 audi         a4           2.8  1999     6 manu… f        18    26 p     comp…
##  7 audi         a4           3.1  2008     6 auto… f        18    27 p     comp…
##  8 audi         a4 quattro   1.8  1999     4 manu… 4        18    26 p     comp…
##  9 audi         a4 quattro   1.8  1999     4 auto… 4        16    25 p     comp…
## 10 audi         a4 quattro   2    2008     4 manu… 4        20    28 p     comp…
## # ℹ 224 more rows
mpg |>
  ggplot(aes(displ, hwy, colour = drv)) + 
  geom_point()

mpg |>
  ggplot(aes(displ, hwy, colour = drv, size = cyl)) + 
  geom_point(show.legend = FALSE) + 
  theme_void() + 
  scale_color_brewer()

mpg |>
  ggplot(aes(displ, hwy, colour = drv)) + 
  geom_point(show.legend = FALSE, size = 4) + 
  geom_point(show.legend = FALSE, size = 1, colour = "#222222") + 
  coord_polar() + 
  theme_void() + 
  scale_color_brewer()

Exercise 1

mpg |>
  ggplot(aes(hwy, cty, colour = drv)) + 
  geom_point(show.legend = FALSE, size = 7) + 
  geom_point(show.legend = FALSE, size = 0.5, colour = "lightyellow") + 
  coord_polar() + 
  theme_void() + 
  scale_color_brewer()

End of Exercise 1

set.seed(1)
n <- 50
dat <- tibble(
  x0 = runif(n),
  y0 = runif(n),
  x1 = x0 + runif(n, min = -.2, max = .2),
  y1 = y0 + runif(n, min = -.2, max = .2),
  shade = runif(n), 
  size = runif(n)
)
dat
## # A tibble: 50 × 6
##        x0     y0    x1      y1 shade  size
##     <dbl>  <dbl> <dbl>   <dbl> <dbl> <dbl>
##  1 0.266  0.478  0.327  0.523  0.268 0.762
##  2 0.372  0.861  0.313  0.884  0.219 0.933
##  3 0.573  0.438  0.481  0.370  0.517 0.471
##  4 0.908  0.245  1.11   0.226  0.269 0.604
##  5 0.202  0.0707 0.255  0.0709 0.181 0.485
##  6 0.898  0.0995 0.784 -0.0282 0.519 0.109
##  7 0.945  0.316  0.796  0.328  0.563 0.248
##  8 0.661  0.519  0.652  0.349  0.129 0.499
##  9 0.629  0.662  0.799  0.573  0.256 0.373
## 10 0.0618 0.407  0.101  0.292  0.718 0.935
## # ℹ 40 more rows
dat |> 
  ggplot(aes(
    x = x0,
    y = y0,
    xend = x1,
    yend = y1,
    colour = shade,
    size = size
  )) +
  geom_segment(show.legend = FALSE) +
  coord_polar() +
  scale_y_continuous(expand = c(0, 0)) +
  scale_x_continuous(expand = c(0, 0)) + 
  scale_color_viridis_c() + 
  scale_size(range = c(0, 10)) + 
  theme_void()
## Warning: Using `size` aesthetic for lines was deprecated in ggplot2 3.4.0.
## ℹ Please use `linewidth` instead.
## This warning is displayed once every 8 hours.
## Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
## generated.

polar_art <- function(seed, n, palette) {
  
  # set the state of the random number generator
  set.seed(seed)
  
  # data frame containing random values for 
  # aesthetics we might want to use in the art
  dat <- tibble(
    x0 = runif(n),
    y0 = runif(n),
    x1 = x0 + runif(n, min = -.2, max = .2),
    y1 = y0 + runif(n, min = -.2, max = .2),
    shade = runif(n), 
    size = runif(n)
  )
  
  # plot segments in various colours, using 
  # polar coordinates and a gradient palette
  dat |> 
    ggplot(aes(
      x = x0,
      y = y0,
      xend = x1,
      yend = y1,
      colour = shade,
      size = size
    )) +
    geom_segment(show.legend = FALSE) +
    coord_polar() +
    scale_y_continuous(expand = c(0, 0)) +
    scale_x_continuous(expand = c(0, 0)) + 
    scale_colour_gradientn(colours = palette) + 
    scale_size(range = c(0, 10)) + 
    theme_void()
}
polar_art(seed = 1, n = 500, palette = c("antiquewhite", "orange", "bisque"))

polar_art(seed = 1, n = 500, palette = c("red", "black", "white"))

polar_art(seed = 2, n = 50, palette = c("red", "black", "white"))

Exercise 2

1.

polar_art(4, 64, palette = c('red', 'white', 'blue'))

polar_art(4, 200, palette = c('red', 'white', 'blue'))

polar_art(110, 100, palette = c('salmon', 'lightyellow', 'lightblue'))

2.

polar_art2 <- function(seed, n, palette) {
  
  # set the state of the random number generator
  set.seed(seed)
  
  # data frame containing random values for 
  # aesthetics we might want to use in the art
  dat <- tibble(
    x0 = runif(n),
    y0 = runif(n),
    x1 = x0 + runif(n, min = -.2, max = .2),
    y1 = y0 + runif(n, min = -.2, max = .2),
    shade = runif(n), 
    size = runif(n)
  )
  
  # plot segments in various colours, using 
  # polar coordinates and a gradient palette
  dat |> 
    ggplot(aes(
      x = x0,
      y = y0,
      xend = x1,
      yend = y1,
      colour = shade,
      size = size
    )) +
    geom_segment(show.legend = FALSE) +
    # removed the polar coordinate
    scale_y_continuous(expand = c(0, 0)) +
    scale_x_continuous(expand = c(0, 0)) + 
    scale_colour_gradientn(colours = palette) + 
    scale_size(range = c(0, 10)) + 
    theme_void()
}
polar_art2(1, 16, palette = c('red', 'white', 'blue'))

polar_art2(4, 200, palette = c('red', 'white', 'blue'))

polar_art2(110, 900, palette = c('salmon', 'lightyellow', 'lightblue'))

End of Exercise 2

library(scales)
library(ggthemes)
pal <- c("#cdb4db", "#ffc8dd", "#ffafcc", "#bde0fe", "#a2d2ff")
show_col(pal)

palette_fn <- colorRampPalette(pal)
palette_fn(100)
##   [1] "#CDB4DB" "#CFB4DB" "#D1B5DB" "#D3B6DB" "#D5B7DB" "#D7B8DB" "#D9B8DB"
##   [8] "#DBB9DB" "#DDBADB" "#DFBBDB" "#E1BCDB" "#E3BCDB" "#E5BDDB" "#E7BEDC"
##  [15] "#E9BFDC" "#EBC0DC" "#EDC0DC" "#EFC1DC" "#F1C2DC" "#F3C3DC" "#F5C4DC"
##  [22] "#F7C4DC" "#F9C5DC" "#FBC6DC" "#FDC7DC" "#FFC7DC" "#FFC6DC" "#FFC5DB"
##  [29] "#FFC4DA" "#FFC3DA" "#FFC2D9" "#FFC1D8" "#FFC0D8" "#FFBFD7" "#FFBED6"
##  [36] "#FFBDD5" "#FFBCD5" "#FFBBD4" "#FFBAD3" "#FFB9D3" "#FFB8D2" "#FFB7D1"
##  [43] "#FFB6D1" "#FFB5D0" "#FFB4CF" "#FFB3CF" "#FFB2CE" "#FFB1CD" "#FFB0CD"
##  [50] "#FFAFCC" "#FDAFCD" "#FBB1CF" "#F8B3D1" "#F5B5D3" "#F3B7D5" "#F0B9D7"
##  [57] "#EDBBD9" "#EBBDDB" "#E8BFDD" "#E5C1DF" "#E3C3E1" "#E0C5E3" "#DDC7E5"
##  [64] "#DBC9E7" "#D8CBE9" "#D5CDEB" "#D3CFED" "#D0D1EF" "#CDD3F1" "#CBD5F3"
##  [71] "#C8D7F5" "#C5D9F7" "#C3DBF9" "#C0DDFB" "#BDDFFD" "#BCDFFE" "#BBDFFE"
##  [78] "#BADEFE" "#B8DDFE" "#B7DDFE" "#B6DCFE" "#B5DCFE" "#B4DBFE" "#B3DBFE"
##  [85] "#B2DAFE" "#B1D9FE" "#B0D9FE" "#AFD8FE" "#AED8FE" "#ACD7FE" "#ABD7FE"
##  [92] "#AAD6FE" "#A9D5FE" "#A8D5FE" "#A7D4FE" "#A6D4FE" "#A5D3FE" "#A4D3FE"
##  [99] "#A3D2FE" "#A2D2FF"
image(
  x = matrix(1:100, ncol = 1), 
  col = palette_fn(100),
  useRaster = TRUE,
  axes = FALSE
)

canva_palettes[[101]]
## [1] "#4abdac" "#fc4a1a" "#f7b733" "#dfdce3"
show_col(canva_palettes[[101]])

sample_canva <- function(seed = NULL) {
  if(!is.null(seed)) set.seed(seed)
  sample(ggthemes::canva_palettes, 1)[[1]]
}
polar_art(seed = 2, n = 100, palette = sample_canva(seed = 2))

polar_art(seed = 2, n = 100, palette = sample_canva(seed = 3))

polar_art(seed = 2, n = 100, palette = sample_canva(seed = 4))

polar_art(seed = 5, n = 100, palette = sample_canva(seed = 1))

polar_art(seed = 6, n = 100, palette = sample_canva(seed = 1))

polar_art(seed = 7, n = 100, palette = sample_canva(seed = 1))

Exercise 3

1.

sample_canva(1)
## [1] "#fcc875" "#baa896" "#e6ccb5" "#e38b75"
sample_canva(2)
## [1] "#080706" "#efefef" "#d1b280" "#594d46"
sample_canva(3)
## [1] "#003b46" "#07575b" "#66a5ad" "#c4dfe6"
show_col(sample_canva(1))

show_col(sample_canva(2))

show_col(sample_canva(3))

2.

sample_named_colours <- function(n) {
  colours <- colours(distinct = TRUE)
  sampled_colours <- sample(colours, size = n)
  return(sampled_colours)
}

# trying polar_art function with palette generator
polar_art(seed = 12, n = 1000, palette = sample_named_colours(8))

3.

random_palette <- function(n) {
  colours <- unlist(ggthemes::canva_palettes)
  sampled_colours <- sample(colours, size = n)
  return(sampled_colours)
}

# trying polar_art function with palette generator
polar_art(seed = 12, n = 1000, palette = random_palette(8))

End of Exercise 3

sample_data <- function(seed = NULL, n = 100){
  if(!is.null(seed)) set.seed(seed)
  dat <- tibble(
    x0 = runif(n),
    y0 = runif(n),
    x1 = x0 + runif(n, min = -.2, max = .2),
    y1 = y0 + runif(n, min = -.2, max = .2),
    shade = runif(n), 
    size = runif(n),
    shape = factor(sample(0:22, size = n, replace = TRUE))
  )
}
polar_styled_plot <- function(data = NULL, palette) {
  ggplot(
    data = data,
    mapping = aes(
      x = x0,
      y = y0,
      xend = x1,
      yend = y1,
      colour = shade,
      size = size
    )) + 
    coord_polar(clip = "off") +
    scale_y_continuous(
      expand = c(0, 0),
      limits = c(0, 1), 
      oob = scales::oob_keep
    ) +
    scale_x_continuous(
      expand = c(0, 0), 
      limits = c(0, 1), 
      oob = scales::oob_keep
    ) + 
    scale_colour_gradientn(colours = palette) + 
    scale_size(range = c(0, 10)) + 
    theme_void() + 
    guides(
      colour = guide_none(),
      size = guide_none(),
      fill = guide_none(),
      shape = guide_none()
    )
}
dat <- sample_data(n = 100, seed = 1) 
pal <- sample_canva(seed = 1)

polar_styled_plot(data = dat, palette = pal) + geom_segment()

polar_styled_plot(data = dat, palette = pal) + geom_path()

polar_styled_plot(data = dat, palette = pal) + geom_point()

library(dplyr)
## 
## Attaching package: 'dplyr'
## The following objects are masked from 'package:stats':
## 
##     filter, lag
## The following objects are masked from 'package:base':
## 
##     intersect, setdiff, setequal, union
dat1 <- sample_data(n = 2000, seed = 123) 
dat2 <- sample_data(n = 100, seed = 456) |>  
  mutate(y0 = .3 + y0 * .6, y1 = .3)

polar_styled_plot(palette = sample_canva(seed = 7)) + 
  geom_segment(
    data = dat1 |> mutate(size = size * 3)
  ) + 
  geom_segment(
    data = dat2 |> mutate(size = size / 5), 
    lineend = "round", 
    colour = "white"
  ) +
  geom_segment(
    data = dat2 |> mutate(size = size / 40), 
    lineend = "round", 
    colour = "#222222"
  ) +
  geom_point(
    data = dat2 |> mutate(size = size * 2),
    colour = "#222222"
  )

dat <- sample_data(n = 2000, seed = 123) |>
  mutate(y1 = y0, size = size / 2)

polar_styled_plot(palette = sample_canva(seed = 456)) + 
  geom_segment(data = dat) + 
  geom_segment(data = dat |> mutate(y1 = y1 - .2, y0 = y0 - .2)) +
  geom_segment(data = dat |> mutate(y1 = y1 - .4, y0 = y0 - .4))

dat <- sample_data(n = 1000, seed = 1) |>
  mutate(y1 = y0, size = size / 4)

polar_styled_plot(palette = sample_canva(seed = 2)) + 
  geom_segment(data = dat, linetype = "331311") 

Exercise 4

1.

dat3 <- sample_data(n = 1233, seed = 113) |>
  mutate(y1 = y0, size = size * 14)

polar_styled_plot(palette = random_palette(3)) + 
  geom_segment(data = dat, linetype = "424242")

2.

normal_styled_plot <- function(data = NULL, palette) {
  ggplot(
    data = data,
    mapping = aes(
      x = x0,
      y = y0,
      xend = x1,
      yend = y1,
      colour = shade,
      size = size *2
    )) +
    scale_y_continuous(
      expand = c(0, 0),
      limits = c(0, 1), 
      oob = scales::oob_keep
    ) +
    scale_x_continuous(
      expand = c(0, 0), 
      limits = c(0, 1), 
      oob = scales::oob_keep
    ) + 
    scale_colour_gradientn(colours = palette) + 
    scale_size(range = c(0, 10)) + 
    theme_void() + 
    guides(
      colour = guide_none(),
      size = guide_none(),
      fill = guide_none(),
      shape = guide_none()
    )
}
# plots a similar thing, but NOT in polar coordinates
normal_styled_plot(palette = random_palette(4)) + 
  geom_segment(data = dat3, linetype = "424242")

End of Exercise 4

Task 2

library(dplyr)
library(purrr)
## 
## Attaching package: 'purrr'
## The following object is masked from 'package:scales':
## 
##     discard
library(tibble)
library(ggplot2)
library(ggthemes)
library(ambient)
sample_canva <- function(seed = NULL) {
  if(!is.null(seed)) set.seed(seed)
  sample(ggthemes::canva_palettes, 1)[[1]]
}
sample_canva()
## [1] "#5f968e" "#bfdccf" "#e05858" "#d5c9b1"
sample_canva()
## [1] "#0f1626" "#ab987a" "#ff533d" "#f5f5f5"
sample_canva()
## [1] "#af4425" "#662e1c" "#ebdcb2" "#c9a66b"
sample_cross_matrix <- function(n = 10, seed = NULL) {
  if(!is.null(seed)) set.seed(seed)
  mat <- matrix(data = 0, nrow = n, ncol = n)
  mat[sample(n, 1), ] <- 1
  mat[, sample(n, 1)] <- 1
  return(mat)
}

sample_cross_matrix()
##       [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10]
##  [1,]    0    0    0    0    0    0    0    1    0     0
##  [2,]    0    0    0    0    0    0    0    1    0     0
##  [3,]    0    0    0    0    0    0    0    1    0     0
##  [4,]    0    0    0    0    0    0    0    1    0     0
##  [5,]    0    0    0    0    0    0    0    1    0     0
##  [6,]    0    0    0    0    0    0    0    1    0     0
##  [7,]    0    0    0    0    0    0    0    1    0     0
##  [8,]    1    1    1    1    1    1    1    1    1     1
##  [9,]    0    0    0    0    0    0    0    1    0     0
## [10,]    0    0    0    0    0    0    0    1    0     0
image(sample_cross_matrix(n = 50), axes = FALSE, useRaster = TRUE)

image(sample_cross_matrix(n = 50), axes = FALSE, useRaster = TRUE)

image(sample_cross_matrix(n = 50), axes = FALSE, useRaster = TRUE)

x_coords <- seq(from = 0, to = 1, length.out = 800)
y_coords <- seq(from = 0, to = 1, length.out = 800)
canvas <- long_grid(x = x_coords, y = y_coords) 
canvas
## # A tibble: 640,000 × 2
##        x       y
##    <dbl>   <dbl>
##  1     0 0      
##  2     0 0.00125
##  3     0 0.00250
##  4     0 0.00375
##  5     0 0.00501
##  6     0 0.00626
##  7     0 0.00751
##  8     0 0.00876
##  9     0 0.0100 
## 10     0 0.0113 
## # ℹ 639,990 more rows
gen_perlin(x = 1:5, y = 1, frequency = .001, seed = 1)
## [1] -0.001000010 -0.001000010 -0.001000009 -0.001000009 -0.001000007
gen_perlin(x = 1:5, y = 1, frequency = .5, seed = 1)
## [1] -0.375  0.000  0.000 -0.250  0.000
canvas <- canvas |> 
  mutate(paint = gen_perlin(x, y, frequency = 10, seed = 1234))
canvas
## # A tibble: 640,000 × 3
##        x       y  paint
##    <dbl>   <dbl>  <dbl>
##  1     0 0       0     
##  2     0 0.00125 0.0125
##  3     0 0.00250 0.0249
##  4     0 0.00375 0.0370
##  5     0 0.00501 0.0489
##  6     0 0.00626 0.0604
##  7     0 0.00751 0.0713
##  8     0 0.00876 0.0817
##  9     0 0.0100  0.0915
## 10     0 0.0113  0.101 
## # ℹ 639,990 more rows
art <- ggplot(canvas, aes(x, y, fill = paint)) + 
  geom_raster(show.legend = FALSE) 
art

art + 
  theme_void() +
  coord_equal()

art + 
  theme_void() +
  coord_equal() +
  scale_x_continuous(expand = c(0, 0)) +
  scale_y_continuous(expand = c(0, 0)) +
  scale_fill_gradientn(colours = sample_canva())

Excerise 1

1.

# chanign gen_perlin to get new results
canvas <- canvas |> 
  mutate(paint = gen_perlin(x, y, frequency = 1, seed = 3068))
canvas
## # A tibble: 640,000 × 3
##        x       y    paint
##    <dbl>   <dbl>    <dbl>
##  1     0 0        0      
##  2     0 0.00125 -0.00125
##  3     0 0.00250 -0.00250
##  4     0 0.00375 -0.00375
##  5     0 0.00501 -0.00501
##  6     0 0.00626 -0.00626
##  7     0 0.00751 -0.00751
##  8     0 0.00876 -0.00876
##  9     0 0.0100  -0.0100 
## 10     0 0.0113  -0.0113 
## # ℹ 639,990 more rows
art <- ggplot(canvas, aes(x, y, fill = paint)) + 
  geom_raster(show.legend = FALSE) 

art

art + 
  theme_void() +
  coord_equal()

art + 
  theme_void() +
  coord_equal() +
  scale_x_continuous(expand = c(0, 0)) +
  scale_y_continuous(expand = c(0, 0)) +
  scale_fill_gradientn(colours = sample_canva())

End of Exercise 1

make_noise_art <- function(
    generator = gen_perlin, 
    frequency = 10, 
    seed = 1234,
    pixels = 2000,
    palette = c("#e5ddc8", "#01949a", "#004369", "#db1f48"), 
    ...
) {
  
  # define the grid
  canvas <- long_grid(
    x = seq(from = 0, to = 1, length.out = pixels),
    y = seq(from = 0, to = 1, length.out = pixels)
  ) 
  
  # use the generator to add paint
  canvas <- canvas |>
    mutate(
      paint = generator(
        x, y, 
        frequency = frequency, 
        seed = seed, 
        ...
      )
    )
  
  # use ggplot2 to draw the picture
  art <- canvas |> 
    ggplot(aes(x, y, fill = paint)) + 
    geom_raster(show.legend = FALSE) +
    theme_void() +
    coord_equal() +
    scale_x_continuous(expand = c(0, 0)) +
    scale_y_continuous(expand = c(0, 0)) +
    scale_fill_gradientn(colours = palette)
  
  return(art)
}
make_noise_art(seed = 1234)

make_noise_art(seed = 1001)

make_noise_art(seed = 9999)

make_noise_art(frequency = 10)

make_noise_art(frequency = 20)

make_noise_art(frequency = 90)

make_noise_art(palette = c("white", "black"))

make_noise_art(palette = sample_canva(seed = 123))

make_noise_art(palette = sample_canva(seed = 456))

make_noise_art(generator = gen_perlin)

make_noise_art(generator = gen_worley)

make_noise_art(generator = gen_waves) 

Exercise 2

# code pulled from the given document

library(here)
## here() starts at /Users/luketodd/Desktop/Rprojects/ES 193DS/art-from-code
sample_canva <- function(seed = NULL) {
  if(!is.null(seed)) set.seed(seed)
  sample(ggthemes::canva_palettes, 1)[[1]]
}

make_noise_art <- function(
    generator = gen_perlin, 
    frequency = 10, 
    seed = 1234,
    pixels = 2000,
    palette = c("#e5ddc8", "#01949a", "#004369", "#db1f48"), 
    ...
) {
  
  # define the grid
  canvas <- long_grid(
    x = seq(from = 0, to = 1, length.out = pixels),
    y = seq(from = 0, to = 1, length.out = pixels)
  ) 
  
  # use the generator to add paint
  canvas <- canvas |>
    mutate(
      paint = generator(
        x, y, 
        frequency = frequency, 
        seed = seed, 
        ...
      )
    )
  
  # use ggplot2 to draw the picture
  art <- canvas |> 
    ggplot(aes(x, y, fill = paint)) + 
    geom_raster(show.legend = FALSE) +
    theme_void() +
    coord_equal() +
    scale_x_continuous(expand = c(0, 0)) +
    scale_y_continuous(expand = c(0, 0)) +
    scale_fill_gradientn(colours = palette)
  
  
  
  
  
  
  # CHANGE IN FILE NAMING SYSTEM
  
  
  # generate a unique filename based on seed and frequency
  filename <- paste0("output/noise-art-seed", seed, "-frequency-", frequency, ".png")
  
  # save the plot to file
  ggsave(
    filename = filename, 
    plot = art,
    width = 1000,
    height = 1000,
    units = "px",
    dpi = 300
  )
  
  return(art)
}
make_noise_art(generator = gen_perlin, seed=402, frequency=12)

make_noise_art(generator = gen_perlin, seed=13, frequency=13)

End of Exercise 2

Exercise 3

sample_canva <- function(seed = NULL) {
  if(!is.null(seed)) set.seed(seed)
  sample(ggthemes::canva_palettes, 1)[[1]]
}

blank_canvas <- long_grid(
  x = seq(from = 0, to = 1, length.out = 2000),
  y = seq(from = 0, to = 1, length.out = 2000)
) 

plot_painted_canvas <- function(canvas, palette = NULL) {
  if(is.null(palette)) {
    palette <- c("#e5ddc8","#01949a","#004369","#db1f48")
  }
  canvas |> 
    ggplot(aes(x, y, fill = paint)) + 
    geom_raster(show.legend = FALSE) +
    theme_void() +
    coord_equal() +
    scale_x_continuous(expand = c(0, 0)) +
    scale_y_continuous(expand = c(0, 0)) +
    scale_fill_gradientn(colours = palette)
}

fractal_art <- function(fractal, generator, palette = NULL, ...) {
  blank_canvas |>
    mutate(
      paint = fracture(
        noise = generator,
        fractal = fractal,
        x = x, 
        y = y, 
        ...
      )
    ) |>
    plot_painted_canvas(palette = palette)
}

1.

fractal_art(fractal = ridged, 
            generator = gen_perlin, 
            freq_init = 2, 
            octaves = 2, 
            seed = 3, 
            palette = c("salmon", "white", "lightblue"))

2.

fractal_art(fractal = ridged, 
            generator = gen_worley, 
            freq_init = 5, 
            octaves = 40, 
            seed = 9876, 
            palette = c("black", "white"))

3.

custom_gain <- function(x) {
  1 / x^3
}

custom_frequency <- function(x) {
  13 * log(x) - 42
}

fractal_art(fractal = billow, 
            generator = gen_perlin, 
            gain_function = custom_gain, 
            frequency_function = custom_frequency,
            octaves = 2,
            seed = 2)

4.

gen_custom <- function(x, y, frequency, seed = NULL, ...) {
  set.seed(seed)
  noise1 <- gen_perlin(x, y, frequency = frequency, seed = seed, ...)
  noise2 <- gen_worley(x, y, seed = seed, ...)
  noise3 <- gen_simplex(x, y, frequency = frequency * 5, seed = seed, ...)
  paint <- (noise1 + noise2 + noise3) / 6
  
  return(paint)
}

fractal_art(fractal = ridged, 
            generator = gen_custom, 
            freq_init = 45, 
            octaves = 15, 
            seed = 32, 
            palette = c("salmon", "white", "lightblue"))

End of Exercise 3

Exercise 4

1.

# curl-art-1.R
library(tictoc)

curl_data <- function(
    data, 
    iterations = 50,
    step_size = .001,
    ...
) {
  
  update <- function(current_state, iteration, ...) {
    curl <- curl_noise(
      x = current_state$x, 
      y = current_state$y,
      generator = fracture,
      ...
    )
    next_state <- current_state |>
      mutate(
        x = x + curl$x * step_size,
        y = y + curl$y * step_size,
        time = time + 1
      )
    return(next_state)
  }
  
  data |> 
    mutate(id = row_number(), time = 1) |>
    accumulate(1:iterations, update, .init = _, ...) |>
    bind_rows()
}

curl_art <- function(...) {
  curl_data(...) |> 
    ggplot(aes(x, y, group = id)) + 
    geom_path() +
    theme_void() + 
    coord_equal() 
}

smol_grid <- long_grid(x = 1:20, y = 1:20)

pic <- smol_grid |>
  mutate(x = normalise(x), y = normalise(y)) |>
  curl_art(noise = gen_simplex, fractal = fbm, octaves = 4, freq_init = .5)

tic()
ggsave(
  filename = here("output", "curl-art-1.png"), 
  plot = pic,
  width = 2000,
  height = 2000,
  units = "px",
  dpi = 300,
  bg = "white"
)
toc()
## 0.83 sec elapsed
curl_data <- function(
    data, 
    iterations = 50,
    step_size = .001,
    ...
) {
  
  update <- function(current_state, iteration, ...) {
    curl <- curl_noise(
      x = current_state$x, 
      y = current_state$y,
      generator = fracture,
      ...
    )
    next_state <- current_state |>
      mutate(
        x = x + curl$x * step_size,
        y = y + curl$y * step_size,
        time = time + 1
      )
    return(next_state)
  }
  
  data |> 
    mutate(id = row_number(), time = 1) |>
    accumulate(1:iterations, update, .init = _, ...) |>
    bind_rows()
}

curl_art <- function(...) {
  curl_data(...) |> 
    ggplot(aes(x, y, group = id)) + 
    geom_path() +
    theme_void() + 
    coord_equal() 
}

custom_curl_data <- function(data) {
  curl_data(
    data = data,
    iterations = 80, 
    octaves = 10,
    fractal = ridged,
    noise = gen_cubic,
    freq_init = 1,
    frequency = ~ . * 1.2,
    gain_init = 1,
    gain = ~ . * .9,
    seed = 1
  )
}

circle <- function(n = 100) {
  tibble(
    theta = 2 * pi * (1:n) / n, 
    x = cos(theta),
    y = sin(theta)
  )
}

dat1 <- circle(5000) |> 
  custom_curl_data()

dat2 <- circle(5000) |>
  mutate(x = x * .99, y = y * .99) |>
  custom_curl_data()

pic <- ggplot(mapping = aes(x, y, group = time)) +
  geom_polygon(data = dat1, fill = "#ffffff10") +
  geom_polygon(data = dat2, fill = "#22222205") +
  theme_void() +
  coord_equal()

tic()
ggsave(
  filename = here("output", "curl-art-2.png"), 
  plot = pic,
  width = 2000,
  height = 2000,
  units = "px",
  dpi = 300,
  bg = "white"
)
toc()
## 4.304 sec elapsed

curl-art-1.R finished in 1.543 seconds whereas curl-art-2.R finished in 5.217 seconds.

2.

custom_curl_data <- function(data) {
  curl_data(
    data = data,
    iterations = 80, 
    octaves = 10,
    fractal = ridged,
    noise = gen_cubic,
    freq_init = 1,
    frequency = ~ . * 1.2,
    gain_init = 1,
    gain = ~ . * .9,
    seed = 1,
    step_size = 0.001 # change step size to make smoother
  )
}

dat1 <- circle(5000) |> 
  custom_curl_data()

dat2 <- circle(5000) |>
  mutate(x = x * .9, y = y * .9) |>
  custom_curl_data()

ggplot(mapping = aes(x, y, group = time)) +
  geom_polygon(data = dat1, fill = "lightblue") +
  geom_polygon(data = dat2, fill = "salmon") +
  theme_void() + 
  coord_equal()

3.

End of Exercise 4

Task 3

Exercise 1

library(ggplot2)
library(tibble)
library(purrr)
library(dplyr)

sample_canva2 <- function(seed = NULL, n = 4) {
  if(!is.null(seed)) set.seed(seed)
  sample(ggthemes::canva_palettes, 1)[[1]] |>
    (\(x) colorRampPalette(x)(n))()  
}

choose_rectangle <- function(blocks) {
  sample(nrow(blocks), 1, prob = blocks$area)
}

choose_break <- function(lower, upper) {
  round((upper - lower) * runif(1))
}

create_rectangles <- function(left, right, bottom, top, value) {
  tibble(
    left = left,
    right = right,
    bottom = bottom,
    top = top,
    width = right - left,
    height = top - bottom,
    area = width * height,
    value = value
  )
}

split_rectangle_x <- function(rectangle, new_value) {
  with(rectangle, {
    split <- choose_break(left, right)
    new_left  <- c(left, left + split)
    new_right <- c(left + split, right)
    new_value <- c(value, new_value)
    create_rectangles(new_left, new_right, bottom, top, new_value)
  })
}

split_rectangle_y <- function(rectangle, new_value) {
  with(rectangle, {
    split <- choose_break(bottom, top)
    new_bottom <- c(bottom, bottom + split)
    new_top <- c(bottom + split, top)
    new_value <- c(value, new_value)
    create_rectangles(left, right, new_bottom, new_top, new_value)
  })
}

split_rectangle <- function(rectangle, value) {
  if(runif(1) < .5) {
    return(split_rectangle_x(rectangle, value))
  }
  split_rectangle_y(rectangle, value)
}

split_block <- function(blocks, value) {
  old <- choose_rectangle(blocks) 
  new <- split_rectangle(blocks[old, ], value)
  bind_rows(blocks[-old, ], new)
}

subdivision <- function(ncol = 500, # decreased
                        nrow = 500, # decreased
                        nsplits = 70, # increased 
                        seed = NULL) {
  
  if(!is.null(seed)) set.seed(seed)
  blocks <- create_rectangles(
    left = 1, 
    right = ncol, 
    bottom = 7, # increased 
    top = nrow, 
    value = 0
  )
  reduce(1:nsplits, split_block, .init = blocks)
}

develop <- function(div, seed = NULL) {
  
  div |> 
    ggplot(aes(
      xmin = left, 
      xmax = right, 
      ymin = bottom, 
      ymax = top,
      fill = value
    )) +
    geom_rect(
      colour = "#ffffff", 
      size = 3,
      show.legend = FALSE
    ) +
    scale_fill_gradientn(
      colours = sample_canva2(seed)
    ) +
    coord_equal() +
    theme_void()
}

pic <- subdivision(seed = 9) |> develop() # different seed 
plot(pic)

Exercise 2

library(ggplot2)
library(tibble)
library(purrr)
library(dplyr)
library(ambient)
library(tidyr)

sample_canva2 <- function(seed = NULL, n = 4) {
  if(!is.null(seed)) set.seed(seed)
  sample(ggthemes::canva_palettes, 1)[[1]] |>
    (\(x) colorRampPalette(x)(n))()  
}

choose_rectangle <- function(blocks) {
  sample(nrow(blocks), 1, prob = blocks$area)
}

choose_break <- function(lower, upper) {
  round((upper - lower) * runif(1))
}

create_rectangles <- function(left, right, bottom, top, value) {
  tibble(
    left = left,
    right = right,
    bottom = bottom,
    top = top,
    width = right - left,
    height = top - bottom,
    area = width * height,
    value = value
  )
}

split_rectangle_x <- function(rectangle, new_value) {
  with(rectangle, {
    split <- choose_break(left, right)
    new_left  <- c(left, left + split)
    new_right <- c(left + split, right)
    new_value <- c(value, new_value)
    create_rectangles(new_left, new_right, bottom, top, new_value)
  })
}

split_rectangle_y <- function(rectangle, new_value) {
  with(rectangle, {
    split <- choose_break(bottom, top)
    new_bottom <- c(bottom, bottom + split)
    new_top <- c(bottom + split, top)
    new_value <- c(value, new_value)
    create_rectangles(left, right, new_bottom, new_top, new_value)
  })
}

split_rectangle <- function(rectangle, value) {
  if(runif(1) < .5) {
    return(split_rectangle_x(rectangle, value))
  }
  split_rectangle_y(rectangle, value)
}

split_block <- function(blocks, value) {
  old <- choose_rectangle(blocks) 
  new <- split_rectangle(blocks[old, ], value)
  bind_rows(blocks[-old, ], new)
}

subdivision <- function(ncol = 1000, 
                        nrow = 1000, 
                        nsplits = 50, 
                        seed = NULL) {
  
  if(!is.null(seed)) set.seed(seed)
  blocks <- create_rectangles(
    left = 1, 
    right = ncol, 
    bottom = 1, 
    top = nrow, 
    value = 0
  )
  reduce(1:nsplits, split_block, .init = blocks)
}

fill_rectangle <- function(left, right, bottom, top, width, 
                           height, area, value, nshades = 100) {
  
  set.seed(value)
  fractals <- list(billow, fbm, ridged)
  generators <- list(gen_simplex, gen_perlin, gen_worley)
  
  expand_grid(
    x = left:right, 
    y = bottom:top, 
  ) |>
    mutate(
      fill = 10 * value + fracture(
        x = x * sample(-3:3, 1),
        y = y * sample(-3:3, 1),
        noise = sample(generators, 1)[[1]],
        fractal = sample(fractals, 1)[[1]],
        octaves = sample(10, 1),
        frequency = sample(10, 1) / 20,
        value = "distance2"
      ) |>
        normalise(to = c(1, nshades)) |> 
        round()
    )
}

draw_mosaic <- function(dat, palette) {
  background <- sample(palette, 1)
  dat |>
    ggplot(aes(x, y, fill = fill)) +
    geom_tile(show.legend = FALSE, colour = background, size = .2) +
    scale_size_identity() +
    scale_colour_gradientn(colours = palette) +
    scale_fill_gradientn(colours = palette) +
    scale_x_continuous(expand = expansion(add = 5)) +
    scale_y_continuous(expand = expansion(add = 5)) +
    coord_equal() +
    theme_void() +
    theme(plot.background = element_rect(fill = background)) 
}

mosaica <- function(ncol = 60, 
                    nrow = 60, 
                    nsplits = 30, 
                    seed = NULL) {
  
  subdivision(ncol, nrow, nsplits, seed) |>
    pmap_dfr(fill_rectangle) |> 
    slice_sample(prop = .995) |>
    filter(!is.na(fill)) |>
    draw_mosaic(palette = sample_canva2(seed))
}

pic <- mosaica(ncol = 100, nsplits = 2220, seed = 1969)
plot(pic)

Exercise 3

library(ggplot2)
library(ggforce)
library(tibble)

set.seed(61)

dat <- tibble(
  x = runif(20),
  y = runif(20),
  val = runif(20)
)

bg_dat <- tibble(
  x = runif(500, min = -.5, max = 1.5),
  y = runif(500, min = -.5, max = 1.5)
)

pic <- ggplot(dat, aes(x, y, fill = val)) +
  coord_equal(xlim = c(-.3, 1.3), ylim = c(-.3, 1.3)) +
  guides(fill = guide_none()) +
  theme_void() + 
  theme(panel.background = element_rect(
    fill = "#222222", colour = "#222222"
  ))

pic2 <- pic + 
  geom_voronoi_tile(
    data = bg_dat,
    fill = "lightyellow", # changed color
    radius = .1, # changed radius
    expand = .0025 # made positive
  ) +
  geom_voronoi_tile(
    colour = "lightyellow", # changed color
    max.radius = 2, # changed max radius
    radius = .02, 
    expand = -.005
  )

plot(pic2)

Exercise 4

library(tibble)
library(purrr)
library(ggplot2)
library(ggforce)

sample_canva2 <- function(seed = NULL, n = 4) {
  if(!is.null(seed)) set.seed(seed)
  sample(ggthemes::canva_palettes, 1)[[1]] |>
    (\(x) colorRampPalette(x)(n))()  
}

unboxy <- function(iterations, layers) {
  
  coeffs <- array(
    data = runif(9 * layers, min = -1, max = 1), 
    dim = c(3, 3, layers)
  )
  
  point0 <- matrix(
    data = runif(3, min = -1, max = 1), 
    nrow = 1,
    ncol = 3
  )
  
  funs <- list(
    function(point) point + (sum(point ^ 2)) ^ (1/3),
    function(point) sin(point),
    function(point) 2 * sin(point)
  )
  
  update <- function(point, t) {
    l <- sample(layers, 1)
    f <- sample(funs, 1)[[1]]
    z <- point[3]
    point[3] <- 1
    point <- f(point %*% coeffs[,,l])
    point[3] <- (point[3] + z)/2
    return(point)
  }
  
  points <- accumulate(1:iterations, update, .init = point0)
  points <- matrix(unlist(points), ncol = 3, byrow = TRUE)
  points <- as_tibble(as.data.frame(points)) 
  names(points) <- c("x", "y", "val")
  return(points)
}

set.seed(1)
dat <- unboxy(iterations = 100, layers = 42) # changed the inputs

pic <- ggplot(dat, aes(x, y, fill = val)) +
  theme_void() + 
  coord_equal(xlim = c(-2.5, 2.5), ylim = c(-2.5, 2.5)) + 
  scale_fill_gradientn(colours = sample_canva2(20)) +  # changed sample_canva2
  scale_x_continuous(expand = c(0, 0)) +
  scale_y_continuous(expand = c(0, 0))

pic2 <- pic +
  geom_voronoi_tile(
    colour = "white", # changed color
    size = 1, # increased size 
    show.legend = FALSE
  )

plot(pic2)

Exercise 5

remotes::install_github("djnavarro/voronoise")
## Skipping install of 'voronoise' from a github remote, the SHA1 (8c9a0f8c) has not changed since last install.
##   Use `force = TRUE` to force installation
library(tibble)
library(purrr)
library(ggplot2)
library(ggforce)
library(voronoise)
library(dplyr)

sample_canva2 <- function(seed = NULL, n = 4) {
  if(!is.null(seed)) set.seed(seed)
  sample(ggthemes::canva_palettes, 1)[[1]] |>
    (\(x) colorRampPalette(x)(n))()  
}

unboxy <- function(iterations, layers) {
  
  coeffs <- array(
    data = runif(9 * layers, min = -1, max = 1), 
    dim = c(3, 3, layers)
  )
  
  point0 <- matrix(
    data = runif(3, min = -1, max = 1), 
    nrow = 1,
    ncol = 3
  )
  
  funs <- list(
    function(point) point + (sum(point ^ 2)) ^ (1/3),
    function(point) sin(point),
    function(point) 2 * sin(point)
  )
  
  update <- function(point, t) {
    l <- sample(layers, 1)
    f <- sample(funs, 1)[[1]]
    z <- point[3]
    point[3] <- 1
    point <- f(point %*% coeffs[,,l])
    point[3] <- (point[3] + z)/2
    return(point)
  }
  
  points <- accumulate(1:iterations, update, .init = point0)
  points <- matrix(unlist(points), ncol = 3, byrow = TRUE)
  points <- as_tibble(as.data.frame(points)) 
  names(points) <- c("x", "y", "val")
  return(points)
}

sift <- function(data) {
  data <- data |>
    group_by(group) |>
    mutate(
      tilesize = (max(x) - min(x)) * (max(y) - min(y)),
      x = if_else(tilesize > .02, x, x + rnorm(1)/10), 
      y = if_else(tilesize > .02, y, y + rnorm(1)/10)
    ) |>
    ungroup()
  return(data)
}

shake <- function(data) {
  data |> 
    group_by(group) |>
    mutate(
      x = x + runif(1), # changed 
      y = y + runif(1)/10
    ) |>
    ungroup()
}

voronoi_baroque <- function(
    seed, 
    perturb, 
    max.radius = NULL, 
    radius = 0, 
    expand = 0,
    ...
) {
  
  set.seed(seed)
  
  blank <- ggplot(mapping = aes(x, y, fill = val)) +
    theme_void() + 
    coord_equal(xlim = c(-2.75, 2.75), ylim = c(-2.75, 2.75)) + 
    guides(fill = guide_none(), alpha = guide_none()) +
    scale_fill_gradientn(colours = sample_canva2(seed)) + 
    scale_alpha_identity() + 
    scale_x_continuous(expand = c(0, 0)) +
    scale_y_continuous(expand = c(0, 0))
  
  blank + 
    geom_voronoise(
      data = unboxy(iterations = 10000, layers = 5),
      perturb = perturb,
      max.radius = max.radius,
      radius = radius,
      expand = expand,
      ...,
      show.legend = FALSE
    )
}

pic <- voronoi_baroque(17, shake)
plot(pic)

Exercise 6

remotes::install_github("paezha/truchet", force=TRUE)
## Downloading GitHub repo paezha/truchet@HEAD
## vctrs (0.6.1 -> 0.6.2) [CRAN]
## dplyr (1.1.1 -> 1.1.2) [CRAN]
## Installing 2 packages: vctrs, dplyr
## 
## The downloaded binary packages are in
##  /var/folders/p3/j253vbkn5k52qr3s8bm127t40000gn/T//Rtmp4mT9mS/downloaded_packages
## Running `R CMD build`...
## * checking for file ‘/private/var/folders/p3/j253vbkn5k52qr3s8bm127t40000gn/T/Rtmp4mT9mS/remotese8df7476f606/paezha-truchet-5f8c93c/DESCRIPTION’ ... OK
## * preparing ‘truchet’:
## * checking DESCRIPTION meta-information ... OK
## * checking for LF line-endings in source and make files and shell scripts
## * checking for empty or unneeded directories
## Removed empty directory ‘truchet/vignettes’
## * building ‘truchet_0.0.0.9007.tar.gz’
library(truchet)
set.seed(123)
mosaic <- st_truchet_ms(
  tiles = c("dr", "tn", "ane"), 
  p1 = .4, # changed scale 1 
  p2 = .2, # changed scale 2
  p3 = .1, # changed scale 3
  xlim = c(1, 6),
  ylim = c(1, 6)
)

pic <- mosaic |> 
  ggplot(aes(fill = color)) +
  geom_sf(color = NA, show.legend = FALSE) + 
  scale_fill_gradientn(colours = c("lightblue", "lightyellow")) + 
  theme_void()

plot(pic)

Task 4

# task 2
canvas <- canvas |> 
  mutate(paint = gen_perlin(x, y, frequency = 1, seed = 3068))
canvas
## # A tibble: 640,000 × 3
##        x       y    paint
##    <dbl>   <dbl>    <dbl>
##  1     0 0        0      
##  2     0 0.00125 -0.00125
##  3     0 0.00250 -0.00250
##  4     0 0.00375 -0.00375
##  5     0 0.00501 -0.00501
##  6     0 0.00626 -0.00626
##  7     0 0.00751 -0.00751
##  8     0 0.00876 -0.00876
##  9     0 0.0100  -0.0100 
## 10     0 0.0113  -0.0113 
## # ℹ 639,990 more rows
art <- ggplot(canvas, aes(x, y, fill = paint)) + 
  geom_raster(show.legend = FALSE) 

sample_canva <- function(seed = NULL) {
  if(!is.null(seed)) set.seed(seed)
  sample(ggthemes::canva_palettes, 1)[[1]]
}

blank_canvas <- long_grid(
  x = seq(from = 0, to = 1, length.out = 2000),
  y = seq(from = 0, to = 1, length.out = 2000)
) 

plot_painted_canvas <- function(canvas, palette = NULL) {
  if(is.null(palette)) {
    palette <- c("#e5ddc8","#01949a","#004369","#db1f48")
  }
  canvas |> 
    ggplot(aes(x, y, fill = paint)) + 
    geom_raster(show.legend = FALSE) +
    theme_void() +
    coord_equal() +
    scale_x_continuous(expand = c(0, 0)) +
    scale_y_continuous(expand = c(0, 0)) +
    scale_fill_gradientn(colours = palette)
}

fractal_art <- function(fractal, generator, palette = NULL, ...) {
  blank_canvas |>
    mutate(
      paint = fracture(
        noise = generator,
        fractal = fractal,
        x = x, 
        y = y, 
        ...
      )
    ) |>
    plot_painted_canvas(palette = palette)
}

fractal_art(fractal = ridged, 
            generator = gen_perlin, 
            freq_init = 2, 
            octaves = 2, 
            seed = 3, 
            palette = c("salmon", "white", "lightblue"))

# task 3
set.seed(123)
mosaic <- st_truchet_ms(
  tiles = c("dr", "tn", "ane"), 
  p1 = .4, # changed scale 1 
  p2 = .2, # changed scale 2
  p3 = .1, # changed scale 3
  xlim = c(1, 6),
  ylim = c(1, 6)
)

pic <- mosaic |> 
  ggplot(aes(fill = color)) +
  geom_sf(color = NA, show.legend = FALSE) + 
  scale_fill_gradientn(colours = c("lightblue", "lightyellow")) + 
  theme_void()

plot(pic)

Conclusion

Essentially everything in this exercise was new to me. I’ve used some of the basic packages like ggplot, dplyr, and the like, but they were used in such different ways than I’m used to. The functions written in this workshop used entirely different logic than I am accustomed to, so it felt very new. Because of this, it allowed me to learn more about functions and the different ways they can be used. However, because of the amount of code that we had sift through for this assignment, I felt that I only really learned about a lot of these ideas on the surface level, and it felt very hard to apply these ideas to create something new in task 4 (I have spent multiple days on this assignment). With that said, I couldn’t really get anything to work for task 4 despite trying multiple different methods.